package com.infore.common.aspect;

import com.alibaba.fastjson.JSON;
import com.infore.common.annotation.RecordLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @Discription TODO
 * @Autor lijianhua
 * @Date 2022/11/5 9:46
 */
@Aspect
@Component
@Slf4j
public class SystemLogAspect {

    /**
     * @within 任何目标对象对应的类型持有RecordLog注解的类方法
     * @annotation 当前执行方法上持有注解RecordLog将被匹配
     */
    @Pointcut("@within(com.infore.common.annotation.RecordLog) || @annotation(com.infore.common.annotation.RecordLog)")
    public  void classAndMethodAspect() {

    }


    @Before("classAndMethodAspect()")
    public void doBefore(JoinPoint joinPoint) {

    }

    /**
     * @within 任何目标对象对应的类型持有RecordLog注解的类方法
     * @annotation 当前执行方法上持有注解RecordLog将被匹配
     * @param joinPoint
     */
//    @Around("@within(com.infore.common.annotation.RecordLog) || @annotation(com.infore.common.annotation.RecordLog)")
    @Around("classAndMethodAspect()")
    public Object around(ProceedingJoinPoint joinPoint){
        Object obj = null;
        String classDescript = "";
        String methodDescript = "";
        try {
            String methodName = joinPoint.getSignature().getName();
            Class<?> targetClass = joinPoint.getTarget().getClass();
            String targetName = targetClass.getName();
            RecordLog classAnnotation = targetClass.getAnnotation(RecordLog.class);
            if(classAnnotation!=null){
                classDescript = classAnnotation.descript();
            }

            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            RecordLog methodAnnotation = method.getAnnotation(RecordLog.class);
            if(methodAnnotation!=null){
                methodDescript = methodAnnotation.descript();
            }
            //获取方法参数
            Object[] arguments = joinPoint.getArgs();
            String jsonString = JSON.toJSONString(arguments);
//            log.info("argments : [{}]",jsonString);
            //记录方法执行时长
            Long begin = System.currentTimeMillis();
            obj = joinPoint.proceed();
            Long end = System.currentTimeMillis();
            Long d = end - begin;
//            log.info("=====方法调用持续时长====={}",d);
            //记录日志
            recordLog(classDescript,methodDescript,d,jsonString,targetName,methodName);
        } catch (Throwable throwable) {
//            throwable.printStackTrace();
            throwable.getMessage();
        }
        return obj;
    }


    @After(value = "classAndMethodAspect()")
    public  void after(JoinPoint joinPoint) {
    }

    @AfterThrowing(pointcut = "classAndMethodAspect()", throwing="e")
    public  void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
        String classDescript = "";
        String methodDescript = "";
        try {
            String methodName = joinPoint.getSignature().getName();
            Class<?> targetClass = joinPoint.getTarget().getClass();
            String targetName = targetClass.getName();
            RecordLog classAnnotation = targetClass.getAnnotation(RecordLog.class);
            if(classAnnotation!=null){
                classDescript = classAnnotation.descript();
            }

            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            RecordLog methodAnnotation = method.getAnnotation(RecordLog.class);
            if(methodAnnotation!=null){
                methodDescript = methodAnnotation.descript();
            }
            //获取方法参数
            Object[] arguments = joinPoint.getArgs();
            String jsonString = JSON.toJSONString(arguments);

            //记录日志
            recordLog(classDescript,methodDescript,null,jsonString,targetName,methodName);
        } catch (Throwable throwable) {
//            throwable.printStackTrace();
            throwable.getMessage();
        }

    }

    @AfterReturning(value = "classAndMethodAspect()", returning="retVal")
    public  void doAfterThrowing(JoinPoint joinPoint, Object retVal) {
    }


    private void recordLog(String classDescript,String methodDescript,Long duration,String args,String className,String methodName){
        //TODO 日志记录业务逻辑
        log.info("=====recordLog===: classDescript={} ; methodDescript={} ; duration={} ; args={} ; className={};methodName={};",
                classDescript,methodDescript,duration,args,className,methodName);
    }



}
